/////////////
// Include //
/////////////

#include "StdAfx.h"
#include ".\XmlExtractor.h"


#define TRY_AGAIN_LIMIT 3

//////////////////////////////
// Construction/Destruction //
//////////////////////////////

XmlExtractor::XmlExtractor() 
{
}

XmlExtractor::~XmlExtractor() {
	freeAlbums();
}

//////////////////
// get set init //
//////////////////

CString	XmlExtractor::getId(void) {
	return id;
}


void	XmlExtractor::initExtractor(CString newid) {
	pages = -1;
	id = newid;
	tryAgain = TRY_AGAIN_LIMIT;
	if (!_albums.IsEmpty()) {
		freeAlbums();
	}
}

int	XmlExtractor::getPages(void) {
	return pages;
}

/////////////////////////
// Independant methods //
/////////////////////////

int		XmlExtractor::loadFile(CString file) {
	
	// Open the file
	CFile fp;
	if (!fp.Open(file, CFile::typeBinary))
		return 0;
	int size;
	if (!(size = (int) fp.GetLength())) {
		fp.Close();
		return 0;
	}

	// Copy the content in a CString
	BYTE	*temp;
	temp =  (BYTE *) malloc(size);
	if (!fp.Read(temp, size))
		return 0;
	fp.Close();
	BYTE	*temp2;
	temp2 =  (BYTE *) malloc(size*2);
	MultiByteToWideChar(CP_UTF8, NULL, (LPCSTR) temp, size, (LPWSTR) temp2, size);
	WideCharToMultiByte(CP_ACP, NULL, (LPCWSTR) temp2, size, (LPSTR) temp, size, NULL, NULL);
	data = temp;
	free(temp);
	free(temp2);


	// Replace the bad characters
	data.Replace("&lt;P>", "\r\n\r\n");
	data.Replace("&lt;BR>", "\r\n");
	data.Replace("&amp;" , "&");	

	// Is it a try again shot?
	if (data.GetAt(1) != '?' && tryAgain){
		pages = -2;
		tryAgain--;
		return 1;
	}

	// Start the parsing
	parse();
	return 1;
}


int XmlExtractor::parse() {
	Album *album;

	int detailsEnd;
	int temp;
	int pos = data.Find("<TotalPages>");
	if (pos == -1) {
		pages = -1;
		pos = 0;
	}
	else {
		pos += 12;
		pages = atoi(data.Mid(pos, data.Find('<', pos) - pos));
	}

	while ((pos = data.Find("<Details url=\"", pos) + 14) > 15) {
		if ((detailsEnd = data.Find("</Details>", pos)) == -1) // In case the file is bad
			break;

		// Create the new album
		album = new Album();
		album->setId(id);
		album->setAmazonLink(data.Mid(pos, data.Find('"', pos) - pos));

		// <Asin>
		pos = data.Find("<Asin>", pos) + 6;
		album->setAsin(data.Mid(pos, data.Find('<', pos)-pos));

		// <ProductName>
		pos = data.Find("<ProductName>", pos) + 13;
		album->setTitle(data.Mid(pos, data.Find('<', pos)-pos));

		//<Artist>
		pos = data.Find("<Artist>", pos) + 8;
		album->setArtist(data.Mid(pos, data.Find('<', pos)-pos));

		//<ReleaseDate>
		if ((temp = data.Find("<ReleaseDate>", pos)) <= detailsEnd && temp != -1) {
			pos = temp +  13;
			album->setDate(data.Mid(pos, data.Find('<', pos)-pos));
		}

		//<ImageUrlMedium>
		if ((temp = data.Find("<ImageUrlMedium>", pos)) <= detailsEnd && temp != -1) {
			pos = temp + 16;
			album->setImageUrl(data.Mid(pos, data.Find('<', pos)-pos));
		}

		//<ImageUrlLarge>
		if ((temp = data.Find("<ImageUrlLarge>", pos)) <= detailsEnd && temp != -1) {
			pos = temp + 15;
			album->setImageLargeUrl(data.Mid(pos, data.Find('<', pos)-pos));
		}

		//<OurPrice>
		if ((temp = data.Find("<OurPrice>", pos)) <= detailsEnd && temp != -1) {
			pos = temp + 10;
			album->setPrice(data.Mid(pos, data.Find('<', pos)-pos));
		}

		//<UsedPrice>
		if ((temp = data.Find("<UsedPrice>", pos)) <= detailsEnd && temp != -1) {
			pos = temp + 11;
			album->setUsedPrice(data.Mid(pos, data.Find('<', pos)-pos));
		}

		while (data.Find("<Track>", pos) != -1 && data.Find("<Track>", pos) < detailsEnd) {
			//<Track>
			pos = data.Find("<Track>", pos) + 7;
			album->setTracks(data.Mid(pos, data.Find('<', pos)-pos));
		}

		//<BrowseName>
		for (int i = 0; i < 2; i++) {
			if ((temp = data.Find("<BrowseName>", pos)) <= detailsEnd && temp != -1) {
				pos = temp + 12;
				album->setGenre(data.Mid(pos, data.Find('<', pos)-pos));
			}
		}
		//<AvgCustomerRating>
		if ((temp = data.Find("<AvgCustomerRating>", pos)) <= detailsEnd && temp != -1) {
			pos = temp + 19;
			album->setAverageRating(data.Mid(pos, data.Find('<', pos)-pos));
		}
		while (data.Find("<Rating>", pos) != -1 && data.Find("<Rating>", pos) < detailsEnd) {
			//<Rating> 
			pos = data.Find("<Rating>", pos) + 8;
			album->setReviewRatings(data.Mid(pos, data.Find('<', pos)-pos));

			//<Summary>
			pos = data.Find("<Summary>", pos) + 9;
			album->setReviewSummaries(data.Mid(pos, data.Find('<', pos)-pos));

			//<Comment>
			pos = data.Find("<Comment>", pos) + 9;
			album->setReviewReviews(data.Mid(pos, data.Find('<', pos)-pos));
		}

		// Add the album to the album list
		_albums.AddHead(album);
	}
	return 0;
}

CList<Album*, Album*>* XmlExtractor::getAlbums(void)
{
	if (_albums.IsEmpty())
		return NULL;
	return &_albums;
}

bool XmlExtractor::freeAlbums(void)
{
	POSITION pos = _albums.GetHeadPosition();
	for (int i = 0; i < _albums.GetCount(); i++)
	{
		delete _albums.GetNext(pos);
	}
	_albums.RemoveAll();
	return true;
}
